/*
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.l2jserver.gameserver.model.entity;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;

import javolution.text.TextBuilder;

import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.datatables.ItemTable;
import com.l2jserver.gameserver.datatables.SkillTable;
import com.l2jserver.gameserver.model.L2ItemInstance;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.base.Experience;
import com.l2jserver.gameserver.network.serverpackets.ExShowScreenMessage;
import com.l2jserver.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
import com.l2jserver.gameserver.network.serverpackets.SocialAction;

/**
*
* @author  TheEnd
* 
*
**/
public class RebirthManager
{
	private static RebirthManager _instance = null;
	
	/** Basically, this will act as a cache so it doesnt have to read DB information on relog. */
	private HashMap<Integer, Integer> _playersRebirthInfo = new HashMap<Integer, Integer>();
	
	/** Creates a new NON-STATIC instance */
	private RebirthManager()
	{
		//Do Nothing ^_-
	}
	
	/** Receives the non-static instance of the RebirthManager.*/
	public static RebirthManager getInstance()
	{
		if (_instance == null)
		{
			_instance = new RebirthManager();
		}
		return _instance;
	}
	
	/** This is what it called from the Bypass Handler. (I think that's all thats needed here).*/
	public void handleCommand(L2PcInstance player, String command)
	{
		if (command.startsWith("custom_rebirth_requestrebirth"))
		{
			displayRebirthWindow(player);
		}
		else if (command.startsWith("custom_rebirth_confirmrequest"))
		{
			requestRebirth(player);
		}
	}
	
	/** Display's an HTML window with the Rebirth Options */
	public void displayRebirthWindow(L2PcInstance player)
	{
		try
		{
			int currBirth = getRebirthLevel(player); //Returns the player's current birth level
			if (currBirth >= 3)
			{//Don't send html if player is already at max rebirth count.
				player.sendMessage("You are currently at your maximum rebirth count!");
				return;
			}
			boolean isMage = player.getBaseTemplate().classId.isMage(); //Returns true if BASE CLASS is a mage.
			L2Skill skill = getRebirthSkill((currBirth + 1), isMage);//Returns the skill based on next Birth and if isMage.
			
			String icon = "" + skill.getId();//Returns the skill's id.
			if (icon.length() < 4)
			{
				icon = "0" + icon;
			}
			
			String playerName = "<font color=FF9900>" + player.getName() + "</font>";//return the player's name.
			
			TextBuilder text = new TextBuilder();
			text.append("<html>");
			text.append("<body>");
			text.append("<center>");
			text.append("<title>- Rebirth Request Menu -</title>");
			text.append("<img src=\"L2UI_CH3.herotower_deco\" width=256 height=32>");
			text.append("<br>");
			text.append("<table border=1 cellspacing=1 cellpadding=1 height=37><tr><td valign=top>");
			text.append("<img src=\"icon.skill3123\" width=32 height=32>");//Cool rebirth icon 'logo' :P
			text.append("</td></tr></table>");
			text.append("<br>");
			text.append("<table width=240 bgcolor=555555 border=1 cellpadding=1 cellspacing=0><tr>");
			text.append("<td height=40 width=35><img src=\"icon.skill" + icon + "\" width=32 height=32 align=left></td>");
			text.append("<td height=40 width=140><center><font color=\"FFFFCC\">Bonus Skill Recieved</font><br1><font color=\"FF9900\">" + skill.getName() + "</font></td>");
			text.append("<td height=40 width=100><center><font color=\"66CC66\">Skill Lvl</font><br1><font color=\"FFFF99\">" + skill.getLevel() + "</font></center></td>");
			text.append("</tr></table>");
			text.append("<br>");
			text.append("<img src=\"L2UI.SquareWhite\" width=\"280\" height=\"1\"><br1>");
			text.append("<table bgcolor=555555 width=270 height=80><tr><td valign=center align=center>- [ <font color=\"66CC66\">Rebirth Information</font> ] -<br1>");
			text.append("<table bgcolor=555555 width=250 height=150><tr><td valign=top align=center><center>");
			text.append("So, " + playerName + ", you wish to be <font color=Level>Reborn</font>? ");
			text.append("Being <font color=Level>Reborn</font> has it's advantages, and it's disadvantages you know. ");
			text.append("When you are <font color=Level>Reborn</font> you are granted a new bonus skill (listed above), ");
			text.append("but your character is reset to level 1 and returned to his starting class. So ");
			text.append("<font color=LEVEL>choose wisely</font> " + playerName + ".<br1>");
			text.append("</center></td></tr></table>");
			text.append("</td></tr></table>");
			text.append("<img src=\"L2UI.SquareWhite\" width=\"280\" height=\"1\"><br>");
			text.append("<center><button value=\" Request Rebirth \" action=\"bypass -h custom_rebirth_confirmrequest\" width=250 height=36 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\">");
			text.append("</center>");
			text.append("</body>");
			text.append("</html>");
			
			NpcHtmlMessage html = new NpcHtmlMessage(1);
			html.setHtml(text.toString());
			player.sendPacket(html);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}
	
	/** Checks to see if the player is eligible for a Rebirth, if so it grants it and stores information */
	public void requestRebirth(L2PcInstance player)
	{
		if (!Config.REBIRTH_ALLOW_REBIRTH)
		{ //See if the Rebirth Engine is currently allowed.
			player.sendMessage("The 'Rebirth Engine' is disabled!");
			return;
		}
		
		else if (player.getLevel() < Config.REBIRTH_MIN_LEVEL)
		{ //Check the player's level.
			player.sendMessage("You do not meet the level requirement for a Rebirth!");
			return;
		}
		
		else if (player.isSubClassActive())
		{
			player.sendMessage("Please switch to your Main Class before attempting a Rebirth.");
			return;
		}
		else if (player.isAlikeDead())
		{
			return;
		}
		else if (player.isAttackingNow())
		{
			return;
		}
		else if (player.isCastingNow())
		{
			return;
		}
		else if (player.isInDuel())
		{
			return;
		}
		
		int currBirth = getRebirthLevel(player);
		int itemNeeded = 0;
		int itemAmount = 0;
		
		if (currBirth >= 3)
		{
			player.sendMessage("You are currently at your maximum rebirth count!");
			return;
		}
		
		switch (currBirth)
		{//Get the requirements
			case 0:
				itemNeeded = Config.REBIRTH_ITEM1_NEEDED;
				itemAmount = Config.REBIRTH_ITEM1_AMOUNT;
				break;
			case 1:
				itemNeeded = Config.REBIRTH_ITEM2_NEEDED;
				itemAmount = Config.REBIRTH_ITEM2_AMOUNT;
				break;
			case 2:
				itemNeeded = Config.REBIRTH_ITEM3_NEEDED;
				itemAmount = Config.REBIRTH_ITEM3_AMOUNT;
				break;
		}
		
		if (itemNeeded != 0)
		{//Their is an item required
			if (!playerIsEligible(player, itemNeeded, itemAmount))
			{//Checks to see if player has required items, and takes them if so.
				return;
			}
		}
		
		boolean firstBirth = currBirth == 0;//Check and see if its the player's first Rebirth calling.
		grantRebirth(player, (currBirth + 1), firstBirth); //Player meets requirements and starts Rebirth Process.
	}
	
	/** Physically rewards player and resets status to nothing. */
	public void grantRebirth(L2PcInstance player, int newBirthCount, boolean firstBirth)
	{
		try
		{
			
			player.removeExpAndSp(player.getExp() - Experience.LEVEL[75], 0);//Set player to level 75.
			player.setClassId(player.getBaseClass());//Resets character to first class.
			for (L2Skill skill : player.getAllSkills())
			{//Remove the player's current skills.
				player.removeSkill(skill);
			}
			player.giveAvailableSkills();//Give players their eligible skills.
			player.store(); //Updates the player's information in the Character Database.
			
			if (firstBirth)
				storePlayerBirth(player);
			else
				updatePlayerBirth(player, newBirthCount);
			
			grantRebirthSkills(player);//Give the player his new Skills.
			displayCongrats(player);//Displays a congratulation message to the player.
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}
	
	/** Special effects when the player levels. */
	public void displayCongrats(L2PcInstance player)
	{
		player.broadcastPacket(new SocialAction(player.getObjectId(), 3));//Victory Social Action.
		MagicSkillUse MSU = new MagicSkillUse(player, player, 2024, 1, 1, 0);//Fireworks Display
		player.broadcastPacket(MSU);
		ExShowScreenMessage screen = new ExShowScreenMessage("Congratulations " + player.getName() + "! You have been Reborn.", 15000);
		player.sendPacket(screen);
	}
	
	/** Check and verify the player DOES have the item required for a request. Also, remove the item if he has.*/
	public boolean playerIsEligible(L2PcInstance player, int itemId, int itemAmount)
	{
		String itemName = ItemTable.getInstance().getTemplate(itemId).getName();
		L2ItemInstance itemNeeded = player.getInventory().getItemByItemId(itemId);
		
		if (itemNeeded == null || itemNeeded.getCount() < itemAmount)
		{
			player.sendMessage("You need atleast " + itemAmount + "  [ " + itemName + " ] to request a Rebirth!");
			return false;
		}
		
		//Player has the required items, so we're going to take them!
		player.getInventory().destroyItem("Rebirth Engine", itemNeeded, itemAmount, player, null);
		player.sendMessage("Removed " + itemAmount + " " + itemName + " from your inventory!");
		return true;
	}
	
	/** Gives the available Bonus Skills to the player. */
	public void grantRebirthSkills(L2PcInstance player)
	{
		int rebirthLevel = getRebirthLevel(player); //returns the current Rebirth Level
		boolean isMage = player.getBaseTemplate().classId.isMage(); //Returns true if BASE CLASS is a mage.
		
		//Simply return since no bonus skills are granted.
		if (rebirthLevel == 0)
			return;
		
		//Load the bonus skills unto the player.
		//CreatureSay rebirthText = null;
		for (int i = 0; i < rebirthLevel; i++)
		{
			L2Skill bonusSkill = getRebirthSkill((i + 1), isMage);
			player.addSkill(bonusSkill, false);
			
		}
	}
	
	/** Return the player's current Rebirth Level */
	public int getRebirthLevel(L2PcInstance player)
	{
		int playerId = player.getObjectId();
		if (_playersRebirthInfo.get(playerId) == null)
		{
			loadRebirthInfo(player);
		}
		return _playersRebirthInfo.get(playerId);
	}
	
	/** Return the L2Skill the player is going to be rewarded. */
	public L2Skill getRebirthSkill(int rebirthLevel, boolean mage)
	{
		L2Skill skill = null;
		if (mage)
		{ //Player is a Mage.
			switch (rebirthLevel)
			{
				case 1:
					skill = SkillTable.getInstance().getInfo(Config.REBIRTH_MAGE_SKILL1_ID, Config.REBIRTH_MAGE_SKILL1_LEVEL);
					break;
				case 2:
					skill = SkillTable.getInstance().getInfo(Config.REBIRTH_MAGE_SKILL2_ID, Config.REBIRTH_MAGE_SKILL2_LEVEL);
					break;
				case 3:
					skill = SkillTable.getInstance().getInfo(Config.REBIRTH_MAGE_SKILL3_ID, Config.REBIRTH_MAGE_SKILL3_LEVEL);
					break;
			}
		}
		else
		{ //Player is a Fighter.
			switch (rebirthLevel)
			{
				case 1:
					skill = SkillTable.getInstance().getInfo(Config.REBIRTH_FIGHTER_SKILL1_ID, Config.REBIRTH_FIGHTER_SKILL1_LEVEL);
					break;
				case 2:
					skill = SkillTable.getInstance().getInfo(Config.REBIRTH_FIGHTER_SKILL2_ID, Config.REBIRTH_FIGHTER_SKILL2_LEVEL);
					break;
				case 3:
					skill = SkillTable.getInstance().getInfo(Config.REBIRTH_FIGHTER_SKILL3_ID, Config.REBIRTH_FIGHTER_SKILL3_LEVEL);
					break;
			}
		}
		return skill;
	}
	
	/** Database caller to retrieve player's current Rebirth Level */
	public void loadRebirthInfo(L2PcInstance player)
	{
		int playerId = player.getObjectId();
		int rebirthCount = 0;
		
		java.sql.Connection con = null;
		try
		{
			ResultSet rset;
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con.prepareStatement("SELECT * FROM `rebirth_manager` WHERE playerId = ?");
			statement.setInt(1, playerId);
			rset = statement.executeQuery();
			
			while (rset.next())
			{
				rebirthCount = rset.getInt("rebirthCount");
			}
			
			rset.close();
			statement.close();
			
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		finally
		{
			try
			{
				con.close();
			}
			catch (Exception e)
			{
			}
		}
		_playersRebirthInfo.put(playerId, rebirthCount);
	}
	
	/** Stores the player's information in the DB. */
	public void storePlayerBirth(L2PcInstance player)
	{
		java.sql.Connection con = null;
		try
		{
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con.prepareStatement("INSERT INTO `rebirth_manager` (playerId,rebirthCount) VALUES (?,1)");
			statement.setInt(1, player.getObjectId());
			statement.execute();
			
			_playersRebirthInfo.put(player.getObjectId(), 1);
			
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		finally
		{
			try
			{
				con.close();
			}
			catch (Exception e)
			{
			}
		}
	}
	
	/** Updates the player's information in the DB. */
	public void updatePlayerBirth(L2PcInstance player, int newRebirthCount)
	{
		java.sql.Connection con = null;
		try
		{
			int playerId = player.getObjectId();
			
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con.prepareStatement("UPDATE `rebirth_manager` SET rebirthCount = ? WHERE playerId = ?");
			statement.setInt(1, newRebirthCount);
			statement.setInt(2, playerId);
			statement.execute();
			
			_playersRebirthInfo.put(playerId, newRebirthCount);
			
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		finally
		{
			try
			{
				con.close();
			}
			catch (Exception e)
			{
			}
		}
	}
}
